package com.wwdx.aop;

import com.wwdx.model.dto.ResultBean;
import com.wwdx.utils.jackson.JsonUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * Rest接口异常处理及日志打印
 * @author liguoliang
 * @date 2018/01/24 13:07
 */
@Aspect
@Component
public class RestControllerAop {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 命名的ThreadLocal指定线程名称
     */
    private NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<>("RestStopTime-RestStartTime");

    /**
     * 注解里要使用的变量只能是常量类型
     */
    private static final String POINT = "execution(public * com.wwdx.controller.rest.*.*(..))";

    @Before(POINT)
    public void doBeforeInServiceLayer(JoinPoint pjp) {
        //1、开始时间
        long beginTime = System.currentTimeMillis();
        //线程绑定变量（该数据只有当前请求的线程可见）
        startTimeThreadLocal.set(beginTime);
    }

    @After(POINT)
    public void doAfterInServiceLayer(JoinPoint pjp) {
        //获取request
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String uri = request.getRequestURI();
        //2、结束时间
        long endTime = System.currentTimeMillis();
        //得到线程绑定的局部变量（开始时间）
        long beginTime = startTimeThreadLocal.get();
        //3、消耗的时间
        long consumeTime = endTime - beginTime;
        long time = 500;
        String filterUri = "/user/duration/add";
        if (consumeTime >= time){
            logger.warn("超出时长500ms的接口地址:{}\t{}ms",uri,consumeTime);
        }else if (!uri.contains(filterUri)){
            logger.info("{}\t{}ms" ,uri,consumeTime);
        }
    }

    @Around(POINT)
    public Object around(ProceedingJoinPoint point) {
        Object result;
        try{
            result = point.proceed();
        }catch (Throwable e){
            logger.error("错误信息：{}\n{}", e.getMessage(),JsonUtils.bean2Json(e.getStackTrace()[0]));
            result = handlerException(e);
        }
        return result;
    }

    private ResultBean handlerException(Throwable e) {
        ResultBean result = new ResultBean();
        result.setMessage(e.getMessage());
        result.setStatus(ResultBean.FAIL);
        return result;
    }
}